#include "s_st7735.h"
#include "h_stm32_hal_defines.h"
#include <stdio.h>

// extern SPI_HandleTypeDef hspi2;

_lcd_dev lcddev;

void s_st7735_spi_write(unsigned char data)
{
	unsigned char i=0;
	for(i=8;i>0;i--)
	{
	  if(data & 0x80)
	  {
	  	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, SET);
	  }
      else
      {
      	HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, RESET);
      }
	   
      // SPI_SCLK_CLR;
      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, RESET);
      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, SET);
      data<<=1; 
	}
}

void s_st7735_delay_ms(unsigned short time)
{
	HAL_Delay(time);
}

void s_st7735_reset_enable(void)
{
	HAL_GPIO_WritePin(SCREEN_RESET_GPIO_Port, SCREEN_RESET_Pin, RESET);
}

void s_st7735_reset_disable(void)
{
	HAL_GPIO_WritePin(SCREEN_RESET_GPIO_Port, SCREEN_RESET_Pin, SET);
}

void s_st7735_led_enable(void)
{
	HAL_GPIO_WritePin(SCREEN_LED_GPIO_Port, SCREEN_LED_Pin, SET);
}

void s_st7735_led_disable(void)
{
	HAL_GPIO_WritePin(SCREEN_LED_GPIO_Port, SCREEN_LED_Pin, RESET);
}

void s_st7735_reset(void)
{
	// s_st7735_reset_disable();
	// s_st7735_delay_ms(500);
	s_st7735_reset_enable();
	s_st7735_delay_ms(500);
	s_st7735_reset_disable();
	s_st7735_delay_ms(500);
}

void s_st7735_write_reg(unsigned char reg)
{
	// unsigned char tdata[1] = {reg};
	HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port, SPI2_NSS_Pin, RESET);
	HAL_GPIO_WritePin(SCREEN_A0_GPIO_Port, SCREEN_A0_Pin, RESET);
	s_st7735_spi_write(reg);
	HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port, SPI2_NSS_Pin, SET);
}

void s_st7735_write_data(unsigned char data)
{
	// unsigned char tdata[1] = {data};
	HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port, SPI2_NSS_Pin, RESET);
	HAL_GPIO_WritePin(SCREEN_A0_GPIO_Port, SCREEN_A0_Pin, SET);
	// HAL_SPI_Transmit(&hspi2, (unsigned char *)tdata, 1, 0xFFFF);
	s_st7735_spi_write(data);
	HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port, SPI2_NSS_Pin, SET);
}

/*
	0 - 0 degree
	1 - 90
	2 - 180
	3 - 270
*/
void s_st7735_set_direction(unsigned char direction)
{ 
			lcddev.setxcmd=0x2A;
			lcddev.setycmd=0x2B;
			lcddev.wramcmd=0x2C;
	switch(direction){		  
		case 0:						 	 		
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;	
			lcddev.xoffset=2;
			lcddev.yoffset=3;	
			s_st7735_write_reg(0x36);//BGR==1,MY==0,MX==0,MV==0
			s_st7735_write_data((1<<3)|(1<<6)|(1<<7));
		break;
		case 1:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			lcddev.xoffset=3;
			lcddev.yoffset=2;
			s_st7735_write_reg(0x36);//BGR==1,MY==0,MX==0,MV==0
			s_st7735_write_data((1<<3)|(1<<7)|(1<<5));
			// s_st7735_write_reg(0x36,(0<<3)|(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
		break;
		case 2:						 	 		
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;	
			lcddev.xoffset=2;
			lcddev.yoffset=1;	
			s_st7735_write_reg(0x36);//BGR==1,MY==0,MX==0,MV==0
			s_st7735_write_data((1<<3)|(0<<6)|(0<<7));
			// s_st7735_write_reg(0x36,(0<<3)|(0<<6)|(0<<7));//BGR==1,MY==0,MX==0,MV==0
		break;
		case 3:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			lcddev.xoffset=1;
			lcddev.yoffset=2;
			s_st7735_write_reg(0x36);//BGR==1,MY==0,MX==0,MV==0
			s_st7735_write_data((1<<3)|(0<<7)|(1<<6)|(1<<5));
			// s_st7735_write_reg(0x36,(0<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
		break;	
		default:break;
	}		
}	

void s_st7735_writeRam(void)
{
	s_st7735_write_reg(0x2C);
}	

void s_st7735_write_16bit_data(unsigned short data)
{	
	// unsigned char t_data[2] = {data >> 8, data};
	unsigned char t_data[2];
	t_data[0] = data >> 8;
	t_data[1] = data;

	HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port, SPI2_NSS_Pin, RESET);
	HAL_GPIO_WritePin(SCREEN_A0_GPIO_Port, SCREEN_A0_Pin, SET);
	// HAL_SPI_Transmit(&hspi2, (unsigned char *)&data, 1, 0xFFFF);
	// HAL_SPI_Transmit(&hspi2, (unsigned char *)&data, 1, 0xFFFF);
	// HAL_SPI_Transmit(&hspi2, t_data, 2, 0xFFFF);
	s_st7735_spi_write(t_data[0]);
	s_st7735_spi_write(t_data[1]);
	HAL_GPIO_WritePin(SPI2_NSS_GPIO_Port, SPI2_NSS_Pin, SET);
}

void s_st7735_set_window(unsigned short xStar, unsigned short yStar,unsigned short xEnd,unsigned short yEnd)
{	
	s_st7735_write_reg(0x2A);	
	s_st7735_write_data(0x00);
	s_st7735_write_data(xStar + lcddev.xoffset);		
	s_st7735_write_data(0x00);
	s_st7735_write_data(xEnd + lcddev.xoffset);

	s_st7735_write_reg(0x2B);	
	s_st7735_write_data(0x00);
	s_st7735_write_data(yStar + lcddev.yoffset);		
	s_st7735_write_data(0x00);
	s_st7735_write_data(yEnd + lcddev.yoffset);

	s_st7735_writeRam();	
}   

void s_st7735_fill_window(unsigned short xStar, unsigned short yStar,unsigned short xEnd,unsigned short yEnd, unsigned short color)
{
	unsigned short i, j;
	s_st7735_set_window(xStar, yStar, xEnd, yEnd);
	for(i = 0; i < xEnd - xStar + 1; i++) {
		for(j = 0; j < yEnd - yStar + 1; j++) {
			// printf("213\r\n");
			s_st7735_write_16bit_data(color);
		}
	}
}
// void s_st7735_clear(unsigned short Color)
// {
// 	unsigned int i,m;  
// 	s_st7735_set_window(0,0,lcddev.width-1,lcddev.height-1);   
// 	for(i=0;i<lcddev.height;i++)
// 	{
// 		for(m=0;m<lcddev.width;m++)
// 		{	
// 			s_st7735_write_16bit_data(Color);
// 		}
// 	}
// } 



signed char s_st7735_init(void)
{
	s_st7735_reset();

	s_st7735_write_reg(0x11);//Sleep exit 
	s_st7735_delay_ms(120);	
	//ST7735R Frame Rate
	s_st7735_write_reg(0xB1); 
	s_st7735_write_data(0x01); 
	s_st7735_write_data(0x2C); 
	s_st7735_write_data(0x2D); 
	s_st7735_write_reg(0xB2); 
	s_st7735_write_data(0x01); 
	s_st7735_write_data(0x2C); 
	s_st7735_write_data(0x2D); 
	s_st7735_write_reg(0xB3); 
	s_st7735_write_data(0x01); 
	s_st7735_write_data(0x2C); 
	s_st7735_write_data(0x2D); 
	s_st7735_write_data(0x01); 
	s_st7735_write_data(0x2C); 
	s_st7735_write_data(0x2D); 	
	s_st7735_write_reg(0xB4); //Column inversion 
	s_st7735_write_data(0x07); 	
	//ST7735R Power Sequence
	s_st7735_write_reg(0xC0); 
	s_st7735_write_data(0xA2); 
	s_st7735_write_data(0x02); 
	s_st7735_write_data(0x84); 
	s_st7735_write_reg(0xC1); 
	s_st7735_write_data(0xC5); 
	s_st7735_write_reg(0xC2); 
	s_st7735_write_data(0x0A); 
	s_st7735_write_data(0x00); 
	s_st7735_write_reg(0xC3); 
	s_st7735_write_data(0x8A); 
	s_st7735_write_data(0x2A); 
	s_st7735_write_reg(0xC4); 
	s_st7735_write_data(0x8A); 
	s_st7735_write_data(0xEE); 
	s_st7735_write_reg(0xC5); //VCOM 
	s_st7735_write_data(0x0E); 	
	s_st7735_write_reg(0x36); //MX, MY, RGB mode 
	s_st7735_write_data(0xC8); 
	//ST7735R Gamma Sequence
	s_st7735_write_reg(0xe0); 
	s_st7735_write_data(0x0f); 
	s_st7735_write_data(0x1a); 
	s_st7735_write_data(0x0f); 
	s_st7735_write_data(0x18); 
	s_st7735_write_data(0x2f); 
	s_st7735_write_data(0x28); 
	s_st7735_write_data(0x20); 
	s_st7735_write_data(0x22); 
	s_st7735_write_data(0x1f); 
	s_st7735_write_data(0x1b); 
	s_st7735_write_data(0x23); 
	s_st7735_write_data(0x37); 
	s_st7735_write_data(0x00); 	
	s_st7735_write_data(0x07); 
	s_st7735_write_data(0x02); 
	s_st7735_write_data(0x10); 
	s_st7735_write_reg(0xe1); 
	s_st7735_write_data(0x0f); 
	s_st7735_write_data(0x1b); 
	s_st7735_write_data(0x0f); 
	s_st7735_write_data(0x17); 
	s_st7735_write_data(0x33); 
	s_st7735_write_data(0x2c); 
	s_st7735_write_data(0x29); 
	s_st7735_write_data(0x2e); 
	s_st7735_write_data(0x30); 
	s_st7735_write_data(0x30); 
	s_st7735_write_data(0x39); 
	s_st7735_write_data(0x3f); 
	s_st7735_write_data(0x00); 
	s_st7735_write_data(0x07); 
	s_st7735_write_data(0x03); 
	s_st7735_write_data(0x10);  	
	s_st7735_write_reg(0x2a);
	s_st7735_write_data(0x00);
	s_st7735_write_data(0x00);
	s_st7735_write_data(0x00);
	s_st7735_write_data(0x7f);
	s_st7735_write_reg(0x2b);
	s_st7735_write_data(0x00);
	s_st7735_write_data(0x00);
	s_st7735_write_data(0x00);
	s_st7735_write_data(0x9f);
	s_st7735_write_reg(0xF0); //Enable test command  
	s_st7735_write_data(0x01); 
	s_st7735_write_reg(0xF6); //Disable ram power save mode 
	s_st7735_write_data(0x00); 	
	s_st7735_write_reg(0x3A); //65k mode 
	s_st7735_write_data(0x05); 
	s_st7735_write_reg(0x29);//Display on	 

	s_st7735_set_direction(0);	

	s_st7735_led_enable();

	// s_st7735_clear(0x00);
	s_st7735_fill_window(0, 0, LCD_W, LCD_H, 0x00);
	
	return 0;
}
